<?php
/**
 * Created by PhpStorm.
 * User: bolle
 * Date: 20.12.15
 * Time: 15:14
 */

namespace tbollmeier\alteraparser\syntaxgraph;


abstract class AbstractVertex
{

    use Clonable;

    abstract public function numSuccessors();

    abstract public function nthSuccessor($idx);

    public function walk($processor)
    {
        $path = [];
        $current = $this;
        $result = null;

        while (true) {

            $result = $processor->process($current, $path);

            if ($result === ProcessingResult::DO_CONTINUE || $result === null) {
                $next = self::doContinue($current, $path);
                if ($next === null) {
                    $next = self::goBack($path, $processor);
                }
            } elseif ($result === ProcessingResult::GO_BACK) {
                $next = self::goBack($path, $processor);
            } else {
                break;
            }

            if ($next === null) {
                break;
            }

            $current = $next;

        }

        return $result;

    }

    private static function doContinue(AbstractVertex $current, &$path)
    {
        if ($current->numSuccessors() > 0) {
            $next = $current->nthSuccessor(0);
            array_push($path, [$current, 0]);
        } else {
            $next = null;
        }

        return $next;
    }

    private static function goBack(&$path, $processor)
    {
        $next = null;

        while (count($path) > 0) {
            $segment = array_pop($path);
            $vertex = $segment[0];
            $idx = $segment[1];
            if ($idx < $vertex->numSuccessors() - 1) {
                $next = $vertex->nthSuccessor($idx + 1);
                array_push($path, [$vertex, $idx + 1]);
                break;
            } else {
                $processor->undo($vertex, $path);
            }
        }

        return $next;

    }

}